#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
HTTP客户端高级使用示例

该示例展示了HTTP客户端模块的高级用法，包括认证、重试、响应解析等。

创建时间: 2023-07-15
作者: Python Tools Team
"""

import os
import sys
import time
from dataclasses import dataclass
from typing import List, Dict, Any, Optional

# 添加项目根目录到Python路径
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../..')))

from modules.http_client import HttpClient, RequestBuilder, ResponseParser
from modules.http_client.auth_handler import BasicAuth, TokenAuth, OAuth2Auth
from modules.http_client.retry_handler import RetryHandler
from modules.http_client.exception import HttpClientException
from modules.logger import LogManager

# 创建日志记录器
logger = LogManager.get_console_logger(name="http_client_advanced_example")


@dataclass
class User:
    """
    用户数据模型
    """
    id: int
    name: str
    email: Optional[str] = None
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'User':
        """
        从字典创建用户对象
        """
        return cls(
            id=data.get('id', 0),
            name=data.get('name', ''),
            email=data.get('email')
        )


def authentication_example():
    """
    认证示例
    """
    logger.info("=== 认证示例 ===")
    
    # 基本认证
    logger.info("基本认证示例...")
    client = HttpClient(base_url="https://httpbin.org")
    
    try:
        # 使用基本认证
        auth = BasicAuth(username="user", password="password")
        response = client.get("/basic-auth/user/password", auth=auth)
        
        logger.info(f"基本认证响应状态码: {response.status_code}")
        logger.info(f"基本认证响应内容: {response.json()}")
        
        # 使用令牌认证
        logger.info("\n令牌认证示例...")
        auth = TokenAuth(token="my-token", token_type="Bearer")
        response = client.get(
            "/headers", 
            auth=auth
        )
        
        logger.info(f"令牌认证请求头: {response.json()['headers']}")
        
        # OAuth2认证（模拟）
        logger.info("\nOAuth2认证示例（模拟）...")
        
        # 模拟令牌刷新回调
        def refresh_callback(refresh_token: str) -> tuple:
            logger.info(f"刷新令牌: {refresh_token}")
            # 模拟令牌刷新过程
            time.sleep(1)
            new_access_token = f"new-access-token-{int(time.time())}"
            new_refresh_token = f"new-refresh-token-{int(time.time())}"
            expires_at = time.time() + 3600  # 1小时后过期
            return new_access_token, new_refresh_token, expires_at
        
        # 创建OAuth2认证处理器
        auth = OAuth2Auth(
            access_token="expired-token",
            refresh_token="refresh-token",
            expires_at=time.time() - 10,  # 已过期
            refresh_callback=refresh_callback
        )
        
        response = client.get("/headers", auth=auth)
        logger.info(f"OAuth2认证请求头: {response.json()['headers']}")
        
    except HttpClientException as e:
        logger.error(f"HTTP请求异常: {e.message}")
        logger.error(f"异常详情: {e.details}")
    finally:
        client.close()


def retry_example():
    """
    重试机制示例
    """
    logger.info("\n=== 重试机制示例 ===")
    
    # 创建重试处理器
    retry_handler = RetryHandler(
        max_retries=3,
        backoff_factor=0.5,
        status_codes=[500, 502, 503, 504, 429],
        methods=['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS']
    )
    
    # 创建带重试机制的HTTP客户端
    client = HttpClient(
        base_url="https://httpbin.org",
        retry_handler=retry_handler
    )
    
    try:
        # 请求可能返回429或5xx的接口
        logger.info("请求可能需要重试的接口...")
        
        # 这里使用httpbin的状态码接口模拟服务器错误
        # 实际情况下，这会返回指定的状态码，不会触发重试
        # 这里仅作为示例说明重试配置
        response = client.get("/status/503")
        
        logger.info(f"响应状态码: {response.status_code}")
        
        # 使用预定义的重试策略
        logger.info("\n使用预定义的重试策略...")
        
        # 激进策略
        aggressive_retry = RetryHandler.aggressive()
        logger.info(f"激进重试策略: 最大重试次数={aggressive_retry.max_retries}, " \
                   f"退避因子={aggressive_retry.backoff_factor}")
        
        # 保守策略
        conservative_retry = RetryHandler.conservative()
        logger.info(f"保守重试策略: 最大重试次数={conservative_retry.max_retries}, " \
                   f"退避因子={conservative_retry.backoff_factor}")
        
    except HttpClientException as e:
        logger.error(f"HTTP请求异常: {e.message}")
        logger.error(f"异常详情: {e.details}")
    finally:
        client.close()


def response_parsing_example():
    """
    响应解析示例
    """
    logger.info("\n=== 响应解析示例 ===")
    
    client = HttpClient(base_url="https://httpbin.org")
    
    try:
        # 解析JSON响应
        logger.info("解析JSON响应...")
        response = client.get("/json")
        json_data = ResponseParser.parse_json(response)
        logger.info(f"解析的JSON数据: {json_data}")
        
        # 解析文本响应
        logger.info("\n解析文本响应...")
        response = client.get("/html")
        text = ResponseParser.parse_text(response)
        logger.info(f"解析的文本数据: {text[:100]}...")
        
        # 使用模型解析响应
        logger.info("\n使用模型解析响应...")
        response = client.get("/json")
        
        # 自定义解析函数
        def parse_user(response):
            data = response.json()
            return User(
                id=1,
                name="Test User",
                email="test@example.com"
            )
        
        user = ResponseParser.parse_with_function(response, parse_user)
        logger.info(f"解析的用户对象: ID={user.id}, 名称={user.name}, 邮箱={user.email}")
        
        # 提取特定字段
        logger.info("\n提取特定字段...")
        response = client.get("/json")
        slide_title = ResponseParser.extract_field(response, "slideshow.title")
        logger.info(f"提取的字段值: {slide_title}")
        
    except HttpClientException as e:
        logger.error(f"HTTP请求异常: {e.message}")
        logger.error(f"异常详情: {e.details}")
    finally:
        client.close()


def file_operations_example():
    """
    文件操作示例
    """
    logger.info("\n=== 文件操作示例 ===")
    
    client = HttpClient(base_url="https://httpbin.org")
    
    try:
        # 下载文件
        logger.info("下载文件示例...")
        download_path = os.path.join(os.path.dirname(__file__), "downloaded_image.png")
        
        # 下载一个图片
        response = client.download_file(
            "/image/png",
            file_path=download_path
        )
        
        logger.info(f"文件下载完成: {download_path}")
        logger.info(f"文件大小: {os.path.getsize(download_path)} 字节")
        
        # 上传文件（模拟）
        logger.info("\n上传文件示例...")
        
        # 使用刚下载的文件进行上传
        response = client.upload_file(
            "/post",
            file_path=download_path,
            file_param_name="file"
        )
        
        logger.info(f"文件上传响应状态码: {response.status_code}")
        logger.info(f"服务器接收到的文件名: {response.json()['files']}")
        
        # 清理下载的文件
        os.remove(download_path)
        logger.info(f"清理下载的文件: {download_path}")
        
    except HttpClientException as e:
        logger.error(f"HTTP请求异常: {e.message}")
        logger.error(f"异常详情: {e.details}")
    except Exception as e:
        logger.error(f"操作异常: {str(e)}")
    finally:
        client.close()


if __name__ == "__main__":
    authentication_example()
    retry_example()
    response_parsing_example()
    file_operations_example()